#include "MainWindow.h"

#include <QDebug>
#include <QAction>
#include <QToolBar>
#include <QFileDialog>
#include <QDockWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QButtonGroup>
#include <QTableWidget>
#include <sstream>
#include <iomanip>

#include "qcustomplot.h"
#include "CurveTableView.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //QRegExp rx("\$\{smp\}");
    QRegExp rx("[");
    rx.setPatternSyntax(QRegExp::Wildcard);
    //qDebug() << rx.exactMatch("${smp}");
    qDebug() << rx.exactMatch("[");

    Init();
}

MainWindow::~MainWindow()
{
}

void MainWindow::SlotImportActionTriggered()
{
    auto fileName = QFileDialog::getOpenFileName(nullptr, "", "", "*.CSV");
    if (fileName.isEmpty())
    {
        return;
    }

    ReadCSVFile(fileName);
    isImported = true;
}

void MainWindow::SlotChannelSelectActionTriggered()
{
    channelSelect->show();
}

void MainWindow::SlotSetActionTriggered()
{
    setWidget->show();
}

void MainWindow::SlotChannelSelectShowPoints(const QStringList &ids)
{
    pointManager->SetShowPoints(ids);
    UpdateCurve();
}

void MainWindow::SlotSetWidgetConfirmButtonClicked(qint64 xRangeMin, qint64 xRangeMax, double yRangeMin, double yRangeMax)
{
    qDebug() << xRangeMin << "," << xRangeMax;
    curvePlot->xAxis->setRange(xRangeMin, xRangeMax);
    curvePlot->yAxis->setRange(yRangeMin, yRangeMax);
    UpdateCurve(false);
}

void MainWindow::SlotButtonGroupIdChecked(int id)
{
    if (curvePlot == nullptr)
    {
        return;
    }
    curvePlot->axisRect()->setRangeZoom(Qt::Orientation(id));
}

void MainWindow::SlotPlotMousePressed(QMouseEvent *event)
{
    QPointF mousePoint = event->pos();
    double cur_x = curvePlot->xAxis->pixelToCoord(mousePoint.x()) * 1000;

    //QDateTime dateTime;
    //dateTime.setMSecsSinceEpoch(cur_x * 1000);

    if (event->button() == Qt::MouseButton::LeftButton)
    {
        leftLine->point1->setTypeX(QCPItemPosition::ptPlotCoords);
        leftLine->point2->setTypeY(QCPItemPosition::ptPlotCoords);
        qDebug() << "llower:" << curvePlot->yAxis->range().lower << ",lupper:" << curvePlot->yAxis->range().upper;
        leftLine->point1->setPixelPosition(mousePoint);
        leftLine->point2->setPixelPosition(QPointF(mousePoint.x(), mousePoint.y() + 1));
        leftLine->setVisible(true);
        curvePlot->replot();
        if (isImported && tableDock != nullptr && !tableDock->isVisible())
        {
            tableDock->setVisible(true);
        }

        {// 更新所有显示点T1
            int index = -1;
            auto times = pointManager->GetTimes();
            double diff = qAbs(times.first().toDouble() - cur_x);

//            std::stringstream ss1;
//            ss1 << std::setprecision(15) << diff;
//            qDebug() << "diff:" << ss1.str().c_str();
            for (int i = 0; i < times.count(); i++)
            {
                auto time = times.at(i).toDouble();
                auto value = qAbs(time - cur_x);

//                std::stringstream ss2;
//                ss2 << std::setprecision(15) << value;
//               qDebug() << "value:" << ss2.str().c_str();

                if (value < diff)
                {
                    diff = value;
                    index = i;
                }
            }

            auto showPoints = pointManager->GetShowPoints();
            for (auto showPoint : showPoints)
            {
                if (showPoint == nullptr)
                {
                    continue;
                }
                auto datas = showPoint->GetDatas();
                if (index != -1 && datas.size() > index)
                {
                    auto t1 = datas.at(index).toDouble();
                    showPoint->SetT1(t1);
                }
            }
        }

        curveTableView->Update();
    }
    else if (event->button() == Qt::MouseButton::RightButton)
    {
        rightLine->point1->setTypeX(QCPItemPosition::ptPlotCoords);
        rightLine->point2->setTypeY(QCPItemPosition::ptPlotCoords);
        rightLine->point1->setPixelPosition(mousePoint);
        rightLine->point2->setPixelPosition(QPointF(mousePoint.x(), mousePoint.y() + 1));
        rightLine->setVisible(true);
        curvePlot->replot();
        if (isImported && tableDock != nullptr && !tableDock->isVisible())
        {
            tableDock->setVisible(true);
        }

        {// 更新所有显示点T2
            int index;
            auto times = pointManager->GetTimes();
            double diff = qAbs(times.first().toDouble() - cur_x);
            for (int i = 0; i < times.count(); i++)
            {
                auto time = times.at(i).toDouble();
                auto value = qAbs(time - cur_x);
                if (value < diff)
                {
                    diff = value;
                    index = i;
                }
            }

            auto showPoints = pointManager->GetShowPoints();
            for (auto showPoint : showPoints)
            {
                if (showPoint == nullptr)
                {
                    continue;
                }
                auto datas = showPoint->GetDatas();
                if (datas.size() > index)
                {
                    auto t2 = datas.at(index).toDouble();
                    showPoint->SetT2(t2);
                }
            }
        }
        curveTableView->Update();
    }
}

void MainWindow::Init()
{
    resize(1920, 1080);
    auto importAction = new QAction(QIcon(":/images/import.png"), QObject::tr("Import"), this);
    auto channelSelectAction = new QAction(QIcon(":/images/channel_select.png"), QObject::tr("Channel Select"), this);
    auto setAction = new QAction(QIcon(":/images/set.png"), QObject::tr("Set"), this);
    auto toolBar = addToolBar(QObject::tr("Device(F)"));
    toolBar->addAction(importAction);
    toolBar->addSeparator();
    toolBar->addAction(channelSelectAction);
    toolBar->addSeparator();
    toolBar->addAction(setAction);

    connect(importAction, &QAction::triggered, this, &MainWindow::SlotImportActionTriggered);
    connect(channelSelectAction, &QAction::triggered, this, &MainWindow::SlotChannelSelectActionTriggered);
    connect(setAction, &QAction::triggered, this, &MainWindow::SlotSetActionTriggered);

    tableDock = new QDockWidget(this);
    tableDock->setFeatures(QDockWidget::DockWidgetMovable);
    tableDock->setAllowedAreas(Qt::AllDockWidgetAreas);
    tableDock->setWindowTitle(QObject::tr("Curve Data"));
    curveTableView = new CurveTableView(this);
    tableDock->setWidget(curveTableView);
    addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, tableDock);
    //tableDock->setVisible(false);

    auto curveDock = new QDockWidget(this);
    curveDock->setFeatures(QDockWidget::DockWidgetMovable);
    curveDock->setAllowedAreas(Qt::AllDockWidgetAreas);
    curveDock->setWindowTitle(QObject::tr("Curve"));
    curvePlot = CreatePlot();
    curveDock->setWidget(curvePlot);
    splitDockWidget(tableDock, curveDock, Qt::Horizontal);

    QList<QDockWidget *> hDocks{ tableDock, curveDock };
    QList<int> hSizes{ 200, 1000 };
    resizeDocks(hDocks, hSizes, Qt::Orientation::Horizontal);

    InitChannelSelectWidget();
    InitSetWidget();

    pointManager = new PointManager(this);
}

void MainWindow::InitChannelSelectWidget()
{
    channelSelect = new ChannelSelectWidget();
    channelSelect->setWindowModality(Qt::WindowModality::ApplicationModal);
    connect(channelSelect, &ChannelSelectWidget::SignalShowPoints, this, &MainWindow::SlotChannelSelectShowPoints);
}

void MainWindow::InitSetWidget()
{
    setWidget = new SetWidget;
    setWidget->setWindowModality(Qt::WindowModality::ApplicationModal);
    connect(setWidget, &SetWidget::SignalConfirmButtonClicked, this, &MainWindow::SlotSetWidgetConfirmButtonClicked);
}

void MainWindow::ReadCSVFile(const QString &fileName)
{
    pointManager->ClearPoints();
    QFile file(fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        qDebug() << "open file failed!";
        return ;
    }
    QTextStream stream(&file);
    QStringList times;
    while (!stream.atEnd())
    {
        auto line = stream.readLine();
        line = line.trimmed();
        if(line.isEmpty()){
            break;
        }
        auto rowData = line.split(',');
        if (pointManager->GetPoints().isEmpty())
        {
            if (rowData.size() <= 4)
            {
                return;
            }
            rowData.removeFirst();
            rowData.removeFirst();
            rowData.removeFirst();
            rowData.removeFirst();
            for (auto name : rowData)
            {
                if (!name.contains("----"))
                {
                    pointManager->AddPoint(name);
                }
            }
            continue;
        }

        if (rowData.size() <= 4)
        {
            continue;
        }
        rowData.takeFirst();
        auto date = rowData.takeFirst();
        auto time = rowData.takeFirst();
        auto ms = rowData.takeFirst();
        auto ls = QString::number(QDateTime(QDate::fromString(date, "yyyy/MM/dd"), QTime::fromString(time, "hh:mm:ss")).toMSecsSinceEpoch() + ms.toUInt());
        times.push_back(ls);
        QStringList datas;
        for (auto data : rowData)
        {
            if (!data.contains("----"))
            {
                datas.push_back(data);
            }
        }
        for (int i = 0; i < datas.size(); i++)
        {
            auto points = pointManager->GetPoints();
            if (i >= points.size())
            {
                continue;
            }
            auto point = points.at(i);
            point->GetDatas().push_back(datas.at(i));
        }
    }
    pointManager->SetTimes(times);
    file.close();
    UpdateCurve();
    auto points = pointManager->GetPoints();
    channelSelect->SetPoints(points);
}

void MainWindow::UpdateCurve(bool isRescale)
{
    curvePlot->clearGraphs();
    auto showPoints = pointManager->GetShowPoints();
    auto times = pointManager->GetTimes();
    for (int i = 0; i < showPoints.count(); i++)
    {
        auto showPoint = showPoints.at(i);
        if (showPoint->GetId() == "-1")
        {
            continue;
        }

        auto graph = curvePlot->addGraph();
        QString color = QString("#%1%2%3%4%5%6").arg(QRandomGenerator::global()->bounded(10) + 3, 0, 16).arg(QRandomGenerator::global()->bounded(10) + 3, 0, 16).arg(QRandomGenerator::global()->bounded(10) + 3, 0, 16)
                .arg(QRandomGenerator::global()->bounded(10) + 3, 0, 16).arg(QRandomGenerator::global()->bounded(10) + 3, 0, 16).arg(QRandomGenerator::global()->bounded(10) + 3, 0, 16);
        QPen pen(color);
        pen.setWidth(1);
        graph->setPen(pen);

        QSharedPointer<QCPGraphDataContainer> container(new QCPGraphDataContainer);
        auto datas = showPoint->GetDatas();
        for (int j = 0; j < datas.size(); j++)
        {
            auto data = datas.at(j);
            auto time = times.at(j);
            container->add(QCPGraphData(time.toDouble() * 0.001, data.toDouble()));
        }

        graph->setData(container);
        if (isRescale == true)
        {
            if (i == 0)
            {
                graph->rescaleAxes();
            }
            else
            {
                graph->rescaleAxes(true);
            }
        }
    }
    curvePlot->replot(QCustomPlot::rpQueuedReplot);

    curveTableView->SetShowPoints(showPoints);
}

QCustomPlot *MainWindow::CreatePlot()
{
    auto plot = new QCustomPlot(this);
    plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

    QSharedPointer<QCPAxisTickerDateTime> timer(new QCPAxisTickerDateTime);
    timer->setDateTimeFormat("yyyy-MM-dd hh:mm:ss.zzz");
    timer->setTickCount(8);
    timer->setTickStepStrategy(QCPAxisTicker::tssMeetTickCount);
    plot->xAxis->setTicker(timer);

    plot->xAxis->grid()->setPen(Qt::NoPen);
    plot->xAxis->grid()->setSubGridPen(Qt::NoPen);
    plot->xAxis->grid()->setZeroLinePen(Qt::NoPen);
    plot->xAxis->setBasePen(QPen(QColor(0, 0, 0, 130), 1, Qt::PenStyle::SolidLine));
    plot->xAxis->setSubTicks(false);
    plot->xAxis->setTickPen(QPen(QColor(0, 0, 0, 38), 1, Qt::PenStyle::SolidLine));
    plot->xAxis->setTickLabelColor(QColor(0, 0, 0, 117));

    plot->yAxis->grid()->setPen(QPen(QColor(0, 0, 0, 38), 1, Qt::PenStyle::SolidLine));
    plot->yAxis->grid()->setSubGridPen(Qt::NoPen);
    plot->yAxis->setBasePen(Qt::NoPen);
    plot->yAxis->setSubTicks(false);
    plot->yAxis->setTickPen(Qt::NoPen);
    plot->yAxis->grid()->setZeroLinePen(Qt::NoPen);
    plot->yAxis->setTickLabelColor(QColor(0, 0, 0, 117));
    QFont font("Microsoft YaHei");
    font.setPixelSize(12);
    plot->yAxis->setTickLabelFont(font);

    plot->axisRect()->setRangeZoom(Qt::Horizontal | Qt::Vertical);

    // init buttongroup
    {
        auto vLayout = new QVBoxLayout;
        vLayout->setSpacing(0);
        auto hLayout = new QHBoxLayout;
        hLayout->setSpacing(0);
        hLayout->setMargin(0);
        auto buttonGroup = new QButtonGroup(this);
        auto allZoomButton = new QPushButton("整体缩放", this);
        allZoomButton->setFixedSize(70, 25);
        allZoomButton->setCheckable(true);
        allZoomButton->setChecked(true);
        auto hZoomButton = new QPushButton("水平缩放", this);
        hZoomButton->setFixedSize(70, 25);
        hZoomButton->setCheckable(true);
        auto vZoomButton = new QPushButton("垂直缩放", this);
        vZoomButton->setFixedSize(70, 25);
        vZoomButton->setCheckable(true);
        hLayout->addStretch();
        hLayout->addWidget(allZoomButton);
        hLayout->addWidget(hZoomButton);
        hLayout->addWidget(vZoomButton);
        buttonGroup->addButton(allZoomButton, (int)(Qt::Orientation::Vertical | Qt::Orientation::Horizontal));
        buttonGroup->addButton(hZoomButton, (int)(Qt::Orientation::Horizontal));
        buttonGroup->addButton(vZoomButton, (int)(Qt::Orientation::Vertical));
        vLayout->addLayout(hLayout);
        vLayout->addStretch();
        plot->setLayout(vLayout);

        connect(buttonGroup, &QButtonGroup::idClicked, this, &MainWindow::SlotButtonGroupIdChecked, Qt::ConnectionType::UniqueConnection);
    }
    connect(plot, &QCustomPlot::mousePress, this, &MainWindow::SlotPlotMousePressed);

    leftLine = new QCPItemStraightLine(plot);
    leftLine->setLayer("overlay");
    leftLine->setClipToAxisRect(true);
    leftLine->setPen(QPen(Qt::red, 1.5, Qt::DotLine));
    leftLine->setVisible(false);
    rightLine = new QCPItemStraightLine(plot);
    rightLine->setLayer("overlay");
    rightLine->setClipToAxisRect(true);
    rightLine->setPen(QPen(Qt::blue, 1.5, Qt::DotLine));
    rightLine->setVisible(false);
    return plot;
}

